package com.nlp.cahe;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.StampedLock;

public class LRUCache2<K,V> extends LinkedHashMap<K, V> {
	private static final long serialVersionUID = 1L;
	
	private static final float DEFAULT_LOAD_FACTOR = 1f;

	private final int maxCapacity;
	private final StampedLock stampedLock = new StampedLock();
	public LRUCache2(int maxCapacity) {
		/**
		 * 第3个参数
		 * false表示维持插入顺序，这样最早插入的将最先被移除。
		 * true表示维持访问顺序，调用get方法后，会将这次访问
		 * 的元素移至链表尾部，删除老元素时会删除表头元素。
		 */
		super(maxCapacity, DEFAULT_LOAD_FACTOR, true);
		this.maxCapacity = maxCapacity;
	}
	@Override
	public V get(Object key) {
		long stamp = stampedLock.tryOptimisticRead();
		if (!stampedLock.validate(stamp)) {
			stamp = stampedLock.readLock();
			try {
				return super.get(key);
			} finally {
				stampedLock.unlockRead(stamp);
			}
		}
		return super.get(key);

	}
	@Override
	protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) {
		//元素个数达到maxCapacity 删除老元素
		return size() > maxCapacity;
	}
	@Override
	public boolean containsKey(Object key) {
		long stamp = stampedLock.tryOptimisticRead();
		if (!stampedLock.validate(stamp)) {
			stamp = stampedLock.readLock();
			try {
				return super.containsKey(key);
			} finally {
				stampedLock.unlockRead(stamp);
			}
		}
		return super.containsKey(key);

	}
	@Override
	public void clear() {
		long stamp = stampedLock.writeLock();
		try {
			super.clear();
		} finally {
			stampedLock.unlock(stamp);
		}
	}
	
	public ArrayList<Map.Entry<K, V>> getAll() {
		long stamp = stampedLock.tryOptimisticRead();
		if (!stampedLock.validate(stamp)) {
			stamp = stampedLock.readLock();
			try {
				return new ArrayList<Map.Entry<K, V>>(super.entrySet());
			} finally {
				stampedLock.unlockRead(stamp);
			}
		}
		return new ArrayList<Map.Entry<K, V>>(super.entrySet());

	}
	@Override
	public V put(K key, V value) {
		long stamp = stampedLock.writeLock();
		try {
			V v = super.put(key, value);
			
			return v;
		} finally {
			stampedLock.unlock(stamp);
		}
	}
	public static void main(String[] args) {
		ExecutorService es = Executors.newFixedThreadPool(100);
		final CountDownLatch latch = new CountDownLatch(100);
		for (int i = 0; i < 100; i++) {
			es.execute(new Runnable() {
				
				public void run() {
					LRUCache2<String, Object> cache = new LRUCache2<String, Object>(10);
					Random random = new Random();
					int n = random.nextInt(99999);
					cache.put(n+"", n);
					latch.countDown();
				}
			});
		}
		try {
			latch.await();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		es.shutdown();
		LRUCache2<String, Object> cache = new LRUCache2<String, Object>(10);
		System.out.println(cache.size());
	}
}
